package com.youlin.service.impl;

import com.youlin.config.MyTX;
import com.youlin.entities.BygAdmin;
import com.youlin.entities.BygDeadMan;
import com.youlin.service.BygAdminService;
import com.youlin.service.MyTestService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicBoolean;

@Service
public class MyTestServiceImpl implements MyTestService {

    @Autowired
    private MyTestService myTestService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private BygAdminService bygAdminService;
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;
    @Autowired
    private MyTX myTX;

    @Override
//    @Transactional(transactionManager = "rabbitTransactionManager")
    public void sendRabbitMsg() {
        String exchange = "HEADERSEXCHANGE";
        String routingKey = "";
        for (int i = 0; i < 10; i++) {
        rabbitTemplate.convertAndSend(exchange, routingKey,
                "convertAndSend ===>> "+routingKey+" ===>> "+i, message -> {
                    message.getMessageProperties().setHeader("vip", true);
                    message.getMessageProperties().setHeader("grade", 12);
                    return message;
                });
        }
//        myTestService.saveJdbc();
        int i = 10/0;
    }

    @Override
    @Transactional
    public void saveJdbc1 () {
        long startTime = System.currentTimeMillis();

        //创建线程屏障
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        AtomicBoolean rollbackFlag = new AtomicBoolean(false);

        CompletableFuture<Void> future1 = CompletableFuture.runAsync(
                myTX.txRunnable(cyclicBarrier, rollbackFlag, () ->
                        bygAdminService.saveOrUpdate(new BygAdmin().setId(1).setName("123456-1")))
        );

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(
                myTX.txRunnable(cyclicBarrier, rollbackFlag, () -> {
                    bygAdminService.saveOrUpdate(new BygAdmin().setId(2).setName("123456-2"));
//                    int i = 10 / 0;
                    bygAdminService.saveOrUpdate(new BygAdmin().setId(3).setName("123456-3"));
        }));

//        myTX.txManager(cyclicBarrier, rollbackFlag, () -> {
//            bygAdminService.saveOrUpdate(new BygAdmin().setId(4).setName("123456-4"));
////            int i = 10/0;
//        });
        try {
            bygAdminService.saveOrUpdate(new BygAdmin().setId(4).setName("123456-4"));
            int i = 10/0;
        } catch (Exception e) {
            rollbackFlag.set(true);
        }finally {
            try {
                cyclicBarrier.await();
            } catch (Exception ex) {}
            if (rollbackFlag.get()) throw new RuntimeException("主线程修改失败");
        }


        System.out.println(System.currentTimeMillis() - startTime);
    }

    @Override
    public void saveJdbc2 () {
        long startTime = System.currentTimeMillis();

        //创建线程屏障
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        AtomicBoolean rollbackFlag = new AtomicBoolean(false);

        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            TransactionStatus transactionStatus1 = dataSourceTransactionManager.getTransaction(transactionDefinition);
            try {
                bygAdminService.saveOrUpdate(new BygAdmin().setId(1).setName("123456-1"));
                System.out.printf("\033[33m future1 ===>> 我干完活了 \033[0m\n");
            }  catch (Exception e) {
                e.printStackTrace();
                System.out.printf("\033[31m future1 ===>> 我错啦，我要回滚了 \033[0m\n");
                rollbackFlag.set(true);
                dataSourceTransactionManager.rollback(transactionStatus1);
            } finally {
                try {
                    System.out.printf("\033[34m future1 ===>> 我已经准备好了，等待中 ··· ··· \033[0m\n");
                    cyclicBarrier.await();
                } catch (Exception e) {}
                if (rollbackFlag.get()) {
                    System.out.printf("\033[31m future1 ===>> 别人错啦，我要回滚了 \033[0m\n");
                    dataSourceTransactionManager.rollback(transactionStatus1);
                } else {
                    System.out.printf("\033[32m future1 ===>> 大家都OK，我要提交了 \033[0m\n");
                    dataSourceTransactionManager.commit(transactionStatus1);
                }
            }
        });

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            TransactionStatus transactionStatus2 = dataSourceTransactionManager.getTransaction(transactionDefinition);
            try {
                bygAdminService.saveOrUpdate(new BygAdmin().setId(2).setName("123456-2"));
                int i = 10/0;
                bygAdminService.saveOrUpdate(new BygAdmin().setId(3).setName("123456-3"));
                System.out.printf("\033[33m future2 ===>> 我干完活了 \033[0m\n");
            } catch (Exception e) {
                e.printStackTrace();
                System.out.printf("\033[31m future2 ===>> 我错啦，我要回滚了 \033[0m\n");
                rollbackFlag.set(true);
                dataSourceTransactionManager.rollback(transactionStatus2);
            } finally {
                try {
                    System.out.printf("\033[34m future2 ===>> 我已经准备好了，等待中 ··· ··· \033[0m\n");
                    cyclicBarrier.await();
                } catch (Exception e) {}
                if (rollbackFlag.get()) {
                    System.out.printf("\033[31m future2 ===>> 别人错啦，我要回滚了 \033[0m\n");
                    dataSourceTransactionManager.rollback(transactionStatus2);
                } else {
                    System.out.printf("\033[32m future2 ===>> 大家都OK，我要提交了 \033[0m\n");
                    dataSourceTransactionManager.commit(transactionStatus2);
                }
            }
        });

        TransactionStatus transactionStatus3 = dataSourceTransactionManager.getTransaction(transactionDefinition);
        try {
            bygAdminService.saveOrUpdate(new BygAdmin().setId(4).setName("123456-4"));
//            int i = 10/0;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.printf("\033[31m main ===>> 我错啦，我要回滚了 \033[0m\n");
            rollbackFlag.set(true);
        } finally {
            try {
                System.out.printf("\033[34m main ===>> 我已经准备好了，等待中 ··· ··· \033[0m\n");
                cyclicBarrier.await();
            } catch (Exception e) {}
            if (rollbackFlag.get()) {
                System.out.printf("\033[31m main ===>> 别人错啦，我要回滚了 \033[0m\n");
                dataSourceTransactionManager.rollback(transactionStatus3);
            } else {
                System.out.printf("\033[32m main ===>> 大家都OK，我要提交了 \033[0m\n");
                dataSourceTransactionManager.commit(transactionStatus3);
            }
        }

        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    }

    @Override
    @Transactional
    public void saveJdbc3_1() {
        bygAdminService.updateById(new BygAdmin().setId(1).setName("123456-1"));

//        boolean b = bygAdminService.updateById(new BygAdmin().setId(123).setName("123456-1"));
//        if (! b) throw new RuntimeException("修改失败");
//        myTestService.saveJdbc3_2();
    }

    @Override
    @Transactional
    public void saveJdbc3_2 () {
        boolean b = bygAdminService.updateById(new BygAdmin().setId(123).setName("123456-1"));
        if (! b) throw new RuntimeException("修改失败");
    }

    @Override
    @Transactional
    public void saveJdbc3_3() {
        myTestService.saveJdbc3_1();

        myTestService.saveJdbc3_2();
    }

    @Override
    public void testTransactionIsolationLevel () {

        TransactionStatus transactionStatus1 = dataSourceTransactionManager.getTransaction(transactionDefinition);
        bygAdminService.saveOrUpdate(new BygAdmin().setId(1).setName("123456-1"));

        System.out.println(bygAdminService.getById(1));

//        dataSourceTransactionManager.commit(transactionStatus1);
        dataSourceTransactionManager.rollback(transactionStatus1);

    }

}
